#include "Map.h"
#include "MapManager.h"
#include "App.h"
#include "ScenePlay.h"

const double Map::c_map_ratio_min = 0.3;
const double Map::c_map_ratio_max = 0.4;

Map::Map(string name, int w, int h, unsigned seed){
	mapUp_ = NULL;
	mapDown_ = NULL;
	this->createNode(name);

	width_ = w;
	height_ = h;
	
	seed_ = seed;

	tilePool_ = new Tile*[width_ * height_];
	memset(tilePool_, 0, sizeof(Tile*)* width_ * height_);
}

Map::~Map(){
	for (unsigned i = 0; i < width_*height_; i++)
	{
		delete tilePool_[i];
		tilePool_[i] = NULL;
	}
	delete tilePool_;
}

void Map::createMap(MapManager* manager, int idFloor, int idWall, int idUnbreakable) {
	srand(seed_);

	int mapSize = width_ * height_;
	typedef char RandomMapFlag;
	RandomMapFlag *bMap = new RandomMapFlag[mapSize];
	memset(bMap, 0, sizeof(RandomMapFlag) * mapSize);

	class RandomMapHelper {
	public:
		int priority_;
		unsigned x_;
		unsigned y_;
		RandomMapHelper(unsigned x, unsigned y) :
			x_(x), y_(y) {
			priority_ = rand();
		}
	};
	auto lLess = [](RandomMapHelper* f, RandomMapHelper* b) ->int { return f->priority_ < b->priority_; };
	priority_queue<RandomMapHelper*, vector<RandomMapHelper*>, decltype(lLess)> q;
	q.push(new RandomMapHelper(width_ / 2, height_/ 2));
	bMap[height_ / 2 * width_ + width_ / 2] = 1;

	
	double frand = (double)rand() / RAND_MAX;
	double ratio = c_map_ratio_min + frand * (c_map_ratio_max - c_map_ratio_min);
	unsigned size = (unsigned)(mapSize * ratio);

	while (size-- && !q.empty()) {
		RandomMapHelper* node = q.top();
		q.pop();
		int x = node->x_;
		int y = node->y_;

		auto lInput = [&](unsigned dx, unsigned dy) {
			if (dx <= 0 || dx >= width_ - 1 || dy <= 0 || dy >= height_ - 1)
				return;
			unsigned coord = width_ * dx + dy;
			if (bMap[coord] != 0)
				return;
			q.push(new RandomMapHelper(dx, dy));
			bMap[coord] = 1;
		};
		lInput(x - 1, y);
		lInput(x + 1, y);
		lInput(x, y - 1);
		lInput(x, y + 1);
	}
	for (unsigned i = 0; i < width_; i++) {
		bMap[i] = -1;
		bMap[(width_ - 1) * height_ + i] = -1;
	}
	for (unsigned i = 1; i < height_ - 1; i++) {
		bMap[i * width_] = -1;
		bMap[(i + 1) * width_ - 1] = -1;
	}

	 while (!q.empty()) {
		RandomMapHelper* rmh = q.top();
		q.pop();
		delete rmh;
	}

	for (unsigned y = 0; y < height_; y++) {
		for (unsigned x = 0; x < width_; x++) {
			int id = 0;
			switch (bMap[width_ * y + x]) {
			case 1: id = idFloor; break;
			case 0: id = idWall; break;
			case -1: id = idUnbreakable; break;
			}
			Tile* t = new Tile(
				*(Tile*)(manager->getOrigin(id))
				);
			t->setPos(x, y);
			setTile(x, y, t);
		}
	}
	delete bMap;
}
